﻿using System.Configuration;
using System.IO;
using Adalbertus.BudgetPlanner.Domain;
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using FluentNHibernate.Conventions.Helpers;
using NHibernate;
using NHibernate.ByteCode.Castle;
using NHibernate.Tool.hbm2ddl;
using Configuration = NHibernate.Cfg.Configuration;

namespace Adalbertus.BudgetPlanner.Infrastructure
{
    public class UnitOfWorkProvider : IUnitOfWorkProvider
    {
        private const string DB_FILE = "BudgetPlanner.db";
        private readonly ISessionFactory _sessionFactory;

        public UnitOfWorkProvider()
        {
            _sessionFactory = CreateSessionFactory();
        }

        private static ISessionFactory CreateSessionFactory()
        {
            ReferByteCode();
            return Fluently.Configure().Database(SQLiteConfiguration.Standard.UsingFile(DB_FILE).ShowSql())
                .Mappings(m =>
                    m.FluentMappings.AddFromAssemblyOf<UnitOfWorkProvider>().Conventions.Add(DefaultLazy.Never())
                )
                .ExposeConfiguration(BuildSchema)
                .BuildSessionFactory();
        }

        private static void BuildSchema(Configuration config)
        {
            bool newDatabaseSchema = ConfigurationManager.AppSettings["NewDatabaseSchema"].ToLowerInvariant() == "true";
#if !DEBUG
            recreateSchema = false;   
#endif
            if (newDatabaseSchema)
            {
                if (File.Exists(DB_FILE))
                {
                    File.Delete(DB_FILE);
                }
            }

            new SchemaExport(config).Create(false, newDatabaseSchema);
        }

        private static void ReferByteCode()
        {
            ProxyFactory fake = new ProxyFactory();
            fake.GetType();
        }

        public IUnitOfWork OpenUnitOfWork()
        {
            return new UnitOfWork(_sessionFactory.OpenSession());
        }

        public void Dispose()
        {
            Dispose(true);
            System.GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                _sessionFactory.Dispose();
            }
        }
    }
}
